package com.pingan.framework.cat.config.internals;

import org.unidal.cat.config.ClientEnvironmentSettings;
import org.unidal.cat.config.internals.DefaultClientEnvironmentSettings;
import org.unidal.cat.config.internals.ServerDiscovery;
import org.unidal.cat.configuration.client.entity.ClientConfig;
import org.unidal.cat.configuration.client.entity.Server;
import org.unidal.helper.Splitters;
import org.unidal.lookup.annotation.Inject;
import org.unidal.lookup.annotation.Named;
import org.unidal.lookup.logging.LogEnabled;
import org.unidal.lookup.logging.Logger;

import java.io.File;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import static org.unidal.cat.CatConstant.ENV_CAT_SERVERS;
import static org.unidal.cat.CatConstant.FILE_CLIENT_XML;
import static org.unidal.cat.CatConstant.FILE_CONFIG_PROPERTIES;
import static org.unidal.cat.CatConstant.KEY_CAT_SERVERS;

@Named(type = ServerDiscovery.class)
public class DefaultServerDiscovery implements ServerDiscovery, LogEnabled {
   @Inject
   private ClientEnvironmentSettings m_settings;

   private Logger m_logger;

   private List<InetSocketAddress> buildAddresses(List<String> servers) {
      List<InetSocketAddress> addresses = new ArrayList<InetSocketAddress>();
      int defaultCatServerPort = m_settings.getDefaultMetaServerPort();

      for (String server : servers) {
         int pos = server.indexOf(':');

         try {
            InetSocketAddress address;

            if (pos < 0) {
               address = new InetSocketAddress(server, defaultCatServerPort);
            } else {
               address = new InetSocketAddress(server.substring(0, pos), Integer.parseInt(server.substring(pos + 1)));
            }

            addresses.add(address);
         } catch (Throwable t) {
            m_logger.warn(String.format("Bad CAT server addresses(%s)!", server), t);
         }
      }

      return addresses;
   }

   @Override
   public void enableLogging(Logger logger) {
      m_logger = logger;
   }

   @Override
   public List<InetSocketAddress> getMetaServers() {
      String servers = getServersFromSystemProperties();

      if (servers == null) {
         servers = getServersFromConfigProperties();
      }

      if (servers == null) {
         servers = getServersFromEnvironmentVariable();
      }

      if (servers == null) {
         servers = getServersFromClientXml();
      }

      if (servers == null) {
         servers = getServersByDetection();
      }

      if (servers == null) {
         servers = getServersFromSettings();
      }

      if (servers == null) {
         return Collections.emptyList();
      } else {
         List<String> list = Splitters.by(',').noEmptyItem().trim().split(servers.replace(';',','));

         return buildAddresses(list);
      }
   }

   protected String getServersByDetection() {
      // Designed to be overridden

      String rtn = null;
      String currentDomain = getCurrentDomain();

      if(currentDomain == null){

         return null;
      }else{
         return currentDomain;
      }

   }

   private String getCurrentDomain(){
      Environment env = Environment.getCurrent();

      Properties properties = new Properties();
      try {
         String resource = "/META-INF/cat/domain.properties";
         InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(resource);

         if (in == null) {
            in = DefaultClientEnvironmentSettings.class.getResourceAsStream(resource);
         }
         properties.load(in);

         return properties.getProperty(env.name());
      }catch (Throwable e){

         return null;
      }
   }

   protected <T> String getServersFromClientXml() {
      ClientConfig config = m_settings.getClientXml();

      if (config != null && config.getServers().size() > 0) {
         StringBuilder sb = new StringBuilder(256);

         for (Server server : config.getServers()) {
            if (sb.length() > 0) {
               sb.append(',');
            }

            sb.append(server.getIp()).append(':').append(server.getHttpPort());
         }

         String servers = sb.toString();
         File file = m_settings.getAbsoluteFile(FILE_CLIENT_XML);

         info("Found CAT servers(%s) from %s", servers, file);
         return servers;
      }

      return null;
   }

   protected String getServersFromConfigProperties() {
      File file = m_settings.getAbsoluteFile(FILE_CONFIG_PROPERTIES);
      String servers = m_settings.getProperty(FILE_CONFIG_PROPERTIES, KEY_CAT_SERVERS, null);

      if (servers != null && servers.length() > 0) {
         info("Found CAT servers(%s) from %s(%s=...)", servers, file, KEY_CAT_SERVERS);
      }

      return servers;
   }

   protected String getServersFromEnvironmentVariable() {
      String servers = System.getenv(ENV_CAT_SERVERS);

      if (servers != null && servers.length() > 0) {
         info("Found CAT servers(%s) from environment variable(%s=...)", servers, ENV_CAT_SERVERS);
      }

      return servers;
   }

   protected String getServersFromSettings() {
      return m_settings.getDefaultMetaServer();
   }

   protected String getServersFromSystemProperties() {
      String servers = System.getProperty(KEY_CAT_SERVERS);

      if (servers != null && servers.length() > 0) {
         info("Found CAT servers(%s) from system properties(-D%s=...)", servers, KEY_CAT_SERVERS);
      }

      return servers;
   }

   private void info(String servers, String pattern, Object... args) {
      String message = String.format(pattern, args);

      m_logger.info(message);
   }
}
